import { CSSProperties, useMemo, useState } from "react";
import { useDrag, useDrop } from "react-dnd";
import { getNanoid } from "@/utils/common";
import { SvgIcon } from "@/components/SvgIcon";
type ListItemType<T> = T & {
  $_id?: string;
  index?: number;
};

interface RenderItemType<T> {
  (item: T, index: number): React.ReactNode;
}

interface Props<T> {
  list: ListItemType<T>[];
  renderItem?: RenderItemType<T>;//list中元素模板
  dragType: string;//drop 时accept的参数
  ulStyle?: CSSProperties;
  liStyle?: CSSProperties;
  doAfterSort?:(list: ListItemType<T>[])=>void,
  cellExtraProps?:Record<string, any>,//补充参数，可应用于业务
}

function DndSortList<T>({ list, renderItem, dragType,ulStyle={},liStyle={},doAfterSort, cellExtraProps={}}: Props<T>) {
  const [listData, setListData]  = useState(list);

  useMemo(() => {
    const arr =list.map((item) => {
      if (!item.$_id) {
        item.$_id = getNanoid(6);
      }
      return item
    });
    setListData(arr)
  }, [list,list.length]);

  const findItem = (id: string) => {
    const listItem = listData.find((item) => item.$_id === id) as ListItemType<T>
    const index= listData.findIndex((item) => item.$_id === id);
    return { listItem, index };
  };
  const changeIndex =  (id: string, to: number) => {
    const {listItem, index} = findItem(id);
    if(!listItem)return
    const arr = [...listData]
    arr.splice(index,1)
    arr.splice(to,0,listItem)
    setListData(arr)
    doAfterSort?.(arr)
  };
  function DSCell(props: ListItemType<T>) {
    const { index, $_id, ...otherProps } = props;
    const [{opacity}, drag, preview] = useDrag({
      type: dragType,
      item: {
        ...props
      },
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
        opacity: monitor.isDragging() ? 0 : 1,
      })
    });
    const [, drop] = useDrop(
      {
        accept: dragType,
        hover(item: ListItemType<T>) {
          if(item.$_id !== props.$_id){
            changeIndex(item.$_id!,index!)
          }
        },
      }
    )
    return (
      <li className="flex mb-3 p-2 rounded-[4px] bg-gray-100" style={{...liStyle,opacity}}
        ref={(node=>preview(drop(node)))}>
        <span ref={drag} className="text-gray-400 h-3 cursor-move">
          <SvgIcon type="icon-drag" style={{fontSize:"16px"}}></SvgIcon>
        </span>
        
        {renderItem === undefined ? (
          Object.keys(otherProps).length>0 ? Object.values(otherProps).join("; ") : index
        ) : (
          renderItem(props, index as number)
        )}
      </li>
    );
  }
  const [, drop] = useDrop( { accept: dragType, } )
  if(list.length===0)return null
  return (
    <ul ref={drop} style={ulStyle} className="px-3 pt-3">
      {listData.map((item, index) => (
        <DSCell key={item.$_id} index={index} {...item} {...cellExtraProps}></DSCell>
      ))}
    </ul>
  );
}

export default DndSortList;
